package org.egomsl.mw.block;

import org.egomsl.mw.Constants;
import org.egomsl.mw.record.Record;
import org.egomsl.mw.record.RecordImpl;
import org.egomsl.mw.record.RecordScanner;

import java.nio.ByteBuffer;

public class BlockImpl implements Block {
    protected boolean finalized;
    protected byte[] recordBytes;
    protected ByteBuffer buffer;

    public BlockImpl() {
        this(Constants.BLOCK_SIZE);
    }

    public BlockImpl(int blockSize) {
        finalized = false;
        recordBytes = new byte[blockSize];
        buffer = ByteBuffer.wrap(recordBytes);
        buffer.position(recordBytes.length);
    }

    public BlockImpl(byte[] bytes, int offset, int len) {
        this.finalized = true;
        this.recordBytes = bytes;
        this.buffer = ByteBuffer.wrap(bytes);
        this.buffer.position(offset);
        this.buffer.limit(offset + len);
    }

    public BlockImpl(ByteBuffer buf) {
        this.finalized = true;
        this.recordBytes = buf.array();
        this.buffer = buf;
    }

    /**
     * 创建引用对象，复用recordBlock的对象，主要用于实现不可修改的快照
     * @param recordBlock
     */
    public BlockImpl(BlockImpl recordBlock) {
        finalized = recordBlock.finalized;
        recordBytes = recordBlock.recordBytes;
        buffer = ByteBuffer.wrap(recordBytes);

        buffer.position(recordBlock.buffer.position());
        buffer.limit(recordBlock.buffer.limit());
    }

    @Override
    public boolean add(Record record) {
        if(finalized) return false;

        int size = record.getDataLen();
        if(buffer.position() < size) return false;

        buffer.position(buffer.position() - size);
        record.writeData(buffer);
        buffer.position(buffer.position() - size);

        return true;
    }

    @Override
    public void clear() {
        buffer.clear();
    }

    @Override
    public boolean isFinalized() {
        return finalized;
    }

    @Override
    public void finalize() {
        finalized = true;
    }

    @Override
    public Block snapshot() {
        BlockImpl recordBlock = new BlockImpl(this);
        recordBlock.finalized = true;
        return recordBlock;
    }

    /**
     * note: all record returned by this scanner is a reuse record by a inner record.
     * @return record scanner instance
     */
    @Override
    public RecordScanner getScanner() {
        return new RecordScannerImpl(this);
    }

    @Override
    public int getOffset() {
        return buffer.position();
    }

    @Override
    public int getLength() {
        return buffer.remaining();
    }

    @Override
    public byte[] getBytes() {
        return recordBytes;
    }

    protected ByteBuffer getBuffer() {
        return buffer;
    }


    class RecordScannerImpl implements RecordScanner {
        private Record record;
        private BlockImpl recordBlock;

        public RecordScannerImpl(BlockImpl recordBlock) {
            record = new RecordImpl();
            this.recordBlock = new BlockImpl(recordBlock);
        }


        @Override
        public boolean hashNext() {
            if(recordBlock.getLength() > 0)
                return true;
            return false;
        }

        @Override
        public Record next() {
            record.clear();
            record.readData(recordBlock.buffer);
            return record;
        }
    }

}
